/*
**NCS provide dev file for the dev objects
**
**This module provide the objects of dev(pp,sig,rx,rcst) 
**
**Copyright (C) 2016-1 andisat <www.andisat.com>
**
**Author: andisat
**Date:2016-1
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include "event.h"
//#include "ncs_list.h"
#include "ncs_log.h"
#include "ncs_network.h"
#include "ncs_sig.h"
#include "ncs_msg.h"
#include "ncs_fsm.h"
#include "ncs_serv.h"
#include "ncs_dev.h"

int dev_if_online(struct dev_obj *dev)
{
    if(dev==NULL)
        return 0;

    if(DEV_TYPE_PP == dev->type
        || DEV_TYPE_SIGEMS == dev->type
        || DEV_TYPE_RXEMS == dev->type)
        return (dev->state == ONLINE)? 1:0;
    else if(DEV_TYPE_RCST == dev->type)
        return (dev->state == RCST_ONLINE
                    || dev->state == RCST_ACTIVE
                    || dev->state == RCST_ONLINE_OPENRX)? 1:0;
}

int rx_if_used(struct dev_obj *rx)
{
    char cnt;
    
    if(!rx || rx->type != DEV_TYPE_RXEMS)
        return FALSE;

    cnt=(char)(rx->flag);

    if(cnt)
        return TRUE;
    else
        return FALSE;
}

int rx_rxpath_used_add(struct dev_obj *rx,char num)
{
    if(!rx || rx->type != DEV_TYPE_RXEMS)
        return -1;

    rx->flag += num;

    return 0;
}

int rx_rxpath_used_dec(struct dev_obj *rx,char num)
{    
    char cnt;
    
    if(!rx || rx->type != DEV_TYPE_RXEMS)
        return -1;

    cnt=(char)(rx->flag);
    if(cnt)
        rx->flag -= num;
    
    return 0;
}


int compare_by_devId(void *val1,void *val2)
{
    int devId;
    struct dev_obj *dev;

    if(!val1 || !val2)
        return -1;

    devId=*((int *)val1);
    dev=(struct dev_obj*)val2;

    if(devId == dev->devId)
        return 0;
    else if(devId < dev->devId)
        return -1;
    else
        return 1;  
}

void dev_free(void *data)
{
    if(data)
        free(data);

    return;
}

struct dev_obj *build_dev()
{
    struct dev_obj *dev=NULL;

    if(dev=(struct dev_obj *)malloc(sizeof(struct dev_obj))){
        memset(dev,0,sizeof(struct dev_obj));
        dev->out = list_new(packet_compare_by_seq,packet_free);
    }

    return dev;
}

void ncs_add_dev(struct list *dev_list,struct dev_obj *dev)
{
    if(dev && dev_list)
        listnode_add(dev_list,dev);
    return;
}

void ncs_del_dev(struct list *dev_list,int devId)
{
    if(dev_list)
        listnode_delete(dev_list,&devId);
    return;
}

struct dev_obj *ncs_get_active_sig(struct ncs_object *ncs)
{
    struct dev_obj *sig=NULL;
    struct list *devlist;
    struct listnode  *node; 

    devlist=ncs->sig_set->dev_list;
    if(ncs)
    {
        LIST_LOOP(devlist,sig,node)
        {
            if(sig->flag == DEV_FLAG_ACTIVE)
                break;
        }            
    }
    
    return sig;
}

struct dev_obj *ncs_find_dev(struct list *dev_list,int devId)
{
    struct dev_obj *dev=NULL;
    listnode node;

    if(dev_list)
    {
        if(node = listnode_lookup(dev_list,(void *)(&devId)))
            dev=(struct dev_obj *)(node->data);
    }
    
    return dev;
}

struct dev_obj *ncs_find_pp(struct ncs_object *ncs,int devId)
{
    if(!ncs)
        return NULL;

    return ncs_find_dev(ncs->pp_set->dev_list,devId);
}


struct dev_obj *ncs_find_sig(struct ncs_object *ncs,int devId)
{
    if(!ncs)
        return NULL;

    return ncs_find_dev(ncs->sig_set->dev_list,devId);
}

struct dev_obj *ncs_find_rx(struct ncs_object *ncs,
    int devId)
{
    if(!ncs)
        return NULL;

    return ncs_find_dev(ncs->rx_set->dev_list,devId);
}

struct dev_obj *ncs_find_rcst(struct ncs_object *ncs,int devId)
{
    if(!ncs)
        return NULL;

    return ncs_find_dev(ncs->rcst_set->dev_list,devId);
}

void ncs_delrcst(struct ncs_object *ncs,struct dev_obj *rcst)
{
    struct dev_obj *dev,*rx;
    struct dev_set *devset;

    struct _STR_CHANNEL_ID_ txcha;
    struct _STR_CHANNEL_ID_ rxcha;

    txcha.devId=rcst->devId;
    txcha.chaId=PATH_FIRST;
    
    if(ncs_getres_by_rcst(&txcha, &rxcha, NULL))
        if(rx=ncs_find_rx(ncs,rxcha.devId))
            ncs2rx_closerxpath_req(ncs, rx, &rxcha);
        
    ncs_relres_by_rcst(&txcha);
    
    devset=ncs->rcst_set;
    if(dev=ncs_find_rcst(ncs, rcst->devId))
    {
        if(dev_if_online(dev))
            devset->count -= 1;
        devset->sum -= 1;
        ncs_del_dev(devset->dev_list,dev->devId);
    }

    del_cfg_modem_db(rcst->devId);
        
    return;
}

void ncs_delrx(struct ncs_object *ncs,struct dev_obj *rx)
{
    struct dev_obj *dev;
    struct dev_set *devset;
    struct _STR_CHANNEL_ID_ rxcha;

    rxcha.devId=rx->devId;
    for(int i=PATH_FIRST;i<=PATH_FOURTH;i++)
    {
        rxcha.chaId=i;
        ncs_closetx_by_rxcha(ncs, &rxcha);
    }
    
    devset=ncs->rx_set;
    if(dev=ncs_find_rx(ncs, rx->devId))
    {
        if(dev_if_online(dev))
            devset->count -= 1;
        devset->sum -= 1;
        ncs_del_dev(devset->dev_list,dev->devId);
    }

    del_cfg_modem_db(rx->devId);
        
    return;
}

void ncs_delsig(struct ncs_object *ncs,struct dev_obj *sig)
{
    struct dev_obj *dev;
    struct dev_set *devset;
    
    devset=ncs->sig_set;
    if(dev=ncs_find_sig(ncs, sig->devId))
    {
        if(dev_if_online(dev))
            devset->count -= 1;
        
        devset->sum -= 1;
        ncs_del_dev(devset->dev_list,dev->devId);
    }

    del_cfg_modem_db(sig->devId);
        
    return;
}

void ncs_del_modem(struct ncs_object *ncs,
    struct dev_obj *modem)
{    
    if(!ncs || !modem)
        return;

    if(modem->type==DEV_TYPE_RCST)
        ncs_delrcst(ncs,modem);
    else if(modem->type==DEV_TYPE_RXEMS)
        ncs_delrx(ncs,modem);
    else if(modem->type==DEV_TYPE_SIGEMS)
        ncs_delsig(ncs,modem);
    else
        return;
}

void ncs_del_pp(struct ncs_object *ncs,
    struct dev_obj *pp)
{
    struct dev_set *ppset;
    
    if(!ncs || !pp)
        return;

    del_cfg_pp_db(pp);
    
    ppset=ncs->pp_set; 
    if(NULL != ncs_find_pp(ncs, pp->devId))
    {
        if(ONLINE == pp->state)
            ppset->count -= 1;
        ppset->sum -= 1;
        ncs_del_dev(ppset->dev_list,pp->devId);
    }

    return;
}

void add_devSet(struct dev_set *devSet)
{
    struct dev_set *set=NULL;
    
    set=(struct dev_set*)malloc(sizeof(struct dev_set));
    if(NULL == set)
        ncs_log(ERR,"%s Add dev_set error ",__func__); 
    else
        memset(set,0,sizeof(struct dev_set));
    
    devSet = set;
    
    return;
}

void del_devSet(struct dev_set *devSet)
{
    if(!devSet)
        ncs_log(WARN,"%s dev_set is NULL ",__func__);
    else{
        list_free(devSet->dev_list);
        free(devSet);
    }
    
    return;
}
void init_devSet(struct dev_set *devSet,char type)
{
    if(!devSet || DEV_TYPE_NULL >= type 
        || type >= DEV_TYPE_MAX)
        return;

    add_devSet(devSet);

    if(DEV_TYPE_NMS == type
        || DEV_TYPE_NCS == type){
       ;
    }
    else if(DEV_TYPE_PP == type)
    {
        devSet->poll=ncs_poll_pp;
        devSet->dev_list=list_new (compare_by_devId,dev_free);
    }
    else if(DEV_TYPE_RXEMS == type)
    {
        devSet->poll=ncs_poll_rx;
        devSet->dev_list=list_new (compare_by_devId,dev_free);
    }
    else if(DEV_TYPE_SIGEMS == type)
    {
        devSet->poll=ncs_poll_sig;
        devSet->dev_list=list_new (compare_by_devId,dev_free);
    }
    else if(DEV_TYPE_RCST == type)
    {
        devSet->poll=ncs_poll_rcst;
        devSet->dev_list=list_new (compare_by_devId,dev_free);
    }else
        ncs_log(INFO,"The devType(%d) is unknow",type);

    return;      
    
}

void free_ncs(struct ncs_object *ncs)
{
    if(!ncs)
        return;

    //del_ncs_db(ncs);
    
    del_devSet(ncs->nms_set);
    del_devSet(ncs->pp_set);
    del_devSet(ncs->sig_set);
    del_devSet(ncs->rx_set);
    del_devSet(ncs->rcst_set);

    //free(ncs);

    return;
}

void init_ncs(struct ncs_object *ncs)
{
    struct event_base *ncs_base;
        
    if(!ncs)
        return;
    
    memset(ncs,0,sizeof(struct ncs_object *));
    
    /*Create gobal ncs base object*/
    ncs_base = event_base_new();
    ncs->g_base = ncs_base;

    /*Add and init ncs network dev_set*/
    init_devSet(ncs->nms_set,DEV_TYPE_NMS);
    init_devSet(ncs->pp_set,DEV_TYPE_PP);
    init_devSet(ncs->sig_set,DEV_TYPE_SIGEMS);
    init_devSet(ncs->rx_set,DEV_TYPE_RXEMS);
    init_devSet(ncs->rcst_set,DEV_TYPE_RCST);


    ncs->ncs_client_recv = ncs_client_recv;
    ncs->ncs_serv_recv = ncs_sigserv_recv;
        
    return; 
}

